#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include "LockGuard.hpp"
#include "Log.hpp"
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include "InetAddr.hpp"

using namespace log_ns;
enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERR
};

static const uint16_t gport = 8888;
static const int gsock = -1;
static const int gbacklog = 8;

using task_t = std::function<void()>;
using cmd_service_t = std::function<void(int sockfd, InetAddr& addr)>; // 回调函数类型
class TcpServer
{
public:
    TcpServer(uint16_t port, cmd_service_t f)
        : _listen_sockfd(gsock),
          _port(port),
          _isrunning(false),
          _service(f)
    {
    }

    void Init()
    {
        // 1.创建 sockfd
        _listen_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sockfd < 0)
        {
            LOG(FATAL, "create sockfd error\n");
            exit(SOCKET_ERROR);
        }
        LOG(INFO, "create sockfd success, sockfd: %d\n", _listen_sockfd);

        // 2.bind
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(_port); // 别忘了转换字节序
        server.sin_addr.s_addr = INADDR_ANY;

        if (::bind(_listen_sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            LOG(FATAL, "bind error\n");
            exit(BIND_ERROR);
        }
        LOG(INFO, "bind success\n");

        // 3.listen
        if (::listen(_listen_sockfd, gbacklog) < 0)
        {
            LOG(FATAL, "listen error\n");
            exit(LISTEN_ERR);
        }
        LOG(INFO, "listen success\n");
    }

    // 线程函数的参数类型
    class ThreadData
    {
    public:
        ThreadData(int sockfd, InetAddr& addr, TcpServer* p)
            : _sockfd(sockfd), 
              _addr(addr), 
              _self(p)
        {}
    public:
        int _sockfd;
        InetAddr _addr;
        TcpServer* _self;
    };

    void Loop()
    {
        // signal(SIGCHLD, SIG_IGN); // 方法1：父进程忽略子进程退出信号

        _isrunning = true;
        while (_isrunning)
        {

            // 4.accept
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = ::accept(_listen_sockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error\n");
                continue; // 等待连接失败，重新等待
            }
            InetAddr addr(client);
            LOG(INFO, "get a new link, client info: %s, sockfd: %d\n", addr.AddrStr().c_str(), sockfd);

            // 与客户端建立连接，开始服务

            // v1, 单进程单线程版本
            // Service(sockfd, addr);

            // v2, 多进程版本
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     if (fork() > 0) exit(0); // 方法2：子进程创建子进程，子进程退出，孙进程变为孤儿进程，执行服务
            //     // 子进程
            //     close(_listen_sockfd);
            //     Service(sockfd, addr);
            //     exit(0);
            // }
            // // 父进程
            // close(sockfd);
            // // 父进程等待子进程成功，继续执行服务
            // int n = waitpid(id, nullptr, 0);
            // if (n > 0)
            // {
            //     LOG(INFO, "wait sucess\n");
            // }

            // // v3, 多线程版本
            pthread_t tid;
            // 因为是静态成员函数，所以需要传递一个类对象指针，方便调用服务
            ThreadData* td = new ThreadData(sockfd, addr, this);
            pthread_create(&tid, nullptr, Excute, td);

            // // v4, 线程池版本
            // task_t t = std::bind(&TcpServer::Service, this, sockfd, addr);
            // ThreadPool<task_t>::GetInstance()->Equeue(t);
        }
    }

    
    // 类成员函数的参数多了一个 this，所以设置为静态成员函数
    static void* Excute(void* args)
    {
        pthread_detach(pthread_self()); // 新线程分离，主线程不用进行等待

        ThreadData* td = static_cast<ThreadData*>(args);
        td->_self->_service(td->_sockfd, td->_addr);
        // 服务结束
        ::close(td->_sockfd);
        delete td;
        return nullptr;
    }

    // void Service(int sockfd, InetAddr &addr)
    // {
    //     while (1) // 长服务
    //     {
    //         // 读取数据
    //         char in_buffer[1024];
    //         int n = read(sockfd, in_buffer, sizeof(in_buffer)-1);
    //         if (n > 0)
    //         {
    //             // 读取成功
    //             in_buffer[n] = 0;
    //             LOG(INFO, "get a message from client: %s, message: %s\n", addr.AddrStr().c_str(), in_buffer);

    //             // 将数据发回客户端
    //             std::string echo_msg = "[server echo] #";
    //             echo_msg += in_buffer;

    //             write(sockfd, echo_msg.c_str(), echo_msg.size());
    //         }
    //         else if (n == 0)
    //         {
    //             // 断开连接
    //             LOG(INFO, "cilent %s quit\n", addr.AddrStr().c_str());
    //             break;
    //         }
    //         else
    //         {
    //             LOG(ERROR, "read error\n");
    //             break;
    //         }
    //     }
    // }

    ~TcpServer()
    {
    }

private:
    int _listen_sockfd;
    uint16_t _port;
    bool _isrunning;
    cmd_service_t _service;
};